import threading
import time
import numpy as np
import MetaTrader5 as mt5
from findpeaks import findpeaks
from control.indicator_control import IndicatorControl
from constant.globl_constant import topList, bottomList, fibList, mvSingal, indicatorSignal, mvTimeframeValue, fibList2, fibList3
from worker.base.base_worker import BaseWorker
from utils.log_util import prints, saveLog
from utils.e_mail import sendMail
from utils.time_util import current_time
import constant.param_config as config


class SignalWorker(BaseWorker):
    """
    信号检测
    """

    lastFibNotice = 0
    lastIndicatorNotice = 0
    lastLevelPrice = 0

    def __init__(self):
        super().__init__()

    def startThread(self):
        thread = threading.Thread(target=self.signal)
        # thread.daemon = True  # 设置线程为守护线程，以便在主程序退出时自动结束线程
        thread.start()

    def signal(self):
        """
        检测信号状态
        """
        prints("信号检测服务已启动...")

        while True:
            if self.isLogin and self.marketClose() is False:
                self.maSignal()
                self.skillIndicatorSignal()
                self.mvIndicatorPrice()
                self.peaksTroughs(mt5.TIMEFRAME_M30, 500)
                self.priceLevel()
                self.fibPrice()
                # self.nineKLine(symble)
            time.sleep(10)

    def peaksTroughs(self, timeFrame, count):
        """
        波峰和波谷
        """

        closeList, sourcePrice, tf = self.getFibPriceList(
            self.symble, timeFrame, count)
        if closeList is not None:
            fp = findpeaks(method='peakdetect', interpolate=10, lookahead=100)
            results = fp.peaks1d(closeList[::-1], x=None, method='peakdetect')
            df = results["df"]
            peakList = df.peak.to_list()[::-1]  # 峰值
            valleyList = df.valley.to_list()[::-1]  # 山谷
            # fp.plot()

            highIndex = -1
            lowIndex = -1
            highList = self.getClosePrice(sourcePrice, "high")
            lowList = self.getClosePrice(sourcePrice, "low")
            currentPrice = mt5.symbol_info_tick(self.symble).ask

            fibList.clear()
            topList.clear()
            bottomList.clear()

            fibOffset = config.getFibOffset()
            for topIndex in range(0, len(peakList)):
                # 存储波峰
                if peakList[topIndex] is True:
                    # 记录第一个符合条件的波峰
                    if highList[
                            topIndex] - fibOffset > currentPrice and highIndex == -1:
                        highIndex = topIndex
                    m = {}
                    m[str(topIndex)] = closeList[topIndex]
                    topList.append(m)

            for bottomIndex in range(0, len(valleyList)):
                # 存储波谷
                if valleyList[bottomIndex] is True:
                    # 记录第一个符合条件的波谷
                    if lowList[
                            bottomIndex] + fibOffset < currentPrice and lowIndex == -1:
                        lowIndex = bottomIndex
                    m = {}
                    m[str(bottomIndex)] = closeList[bottomIndex]
                    bottomList.append(m)

            if highIndex == -1 or lowIndex == -1:
                fibList.clear()
                return

            # 截取第一个高低段的数据
            splitPrice = sourcePrice[0:max([highIndex, lowIndex]) + 10]

            highPrice = max(self.getClosePrice(splitPrice, "high"))
            lowPrice = min(self.getClosePrice(splitPrice, "low"))

            fibList.append(highPrice)
            fibList.append((highPrice - lowPrice) * 0.764 + lowPrice)
            fibList.append((highPrice - lowPrice) * 0.618 + lowPrice)
            fibList.append((highPrice - lowPrice) * 0.5 + lowPrice)
            fibList.append((highPrice - lowPrice) * 0.382 + lowPrice)
            fibList.append((highPrice - lowPrice) * 0.236 + lowPrice)
            fibList.append(lowPrice)

            noticeSpace = config.getNoticeSpace()
            if self.lastFibNotice == 0 or current_time(
            ) - self.lastFibNotice > noticeSpace:
                saveLog("斐波那契数列为：" + "、".join([str(num) for num in fibList]))
                self.lastFibNotice = current_time()
        else:
            self.peaksTroughs(tf, count)

    def fibPrice(self):
        """
        斐波那契
        """
        result = self.getKLine(self.symble, 50, mt5.TIMEFRAME_D1,
                               start=0)["value"]
        todayHigh = result[-1][2]  #今日最高
        todayLow = result[-1][3]  #今日最低

        lastdayHigh = result[-2][2]  #昨日最高
        lastdayLow = result[-2][3]  #昨日最低
        lastdayClose = result[-2][4]  #昨日收盘价

        rangePrice = lastdayHigh - lastdayLow  #昨日价格涨跌幅
        standardPrice = (lastdayHigh + lastdayLow +
                         lastdayClose) / 3.0  #典型价格=（收盘价+最高价+最低价）/3

        # 阻力位
        preventPrice1 = standardPrice + 0.38 * rangePrice
        preventPrice2 = standardPrice + 0.62 * rangePrice
        preventPrice3 = standardPrice + 0.99 * rangePrice

        #支撑位
        supportPrice1 = standardPrice - 0.38 * rangePrice
        supportPrice2 = standardPrice - 0.62 * rangePrice
        supportPrice3 = standardPrice - 0.99 * rangePrice

        centrePrice = (lastdayHigh + lastdayLow + lastdayClose) / 3.0  #多空分水岭

        g_price_244 = 2.0 * centrePrice - lastdayLow
        g_price_316 = 2.0 * centrePrice - lastdayHigh
        g_price_252 = centrePrice + (lastdayHigh - lastdayLow)
        g_price_324 = centrePrice - (lastdayHigh - lastdayLow)
        g_price_260 = 2.0 * centrePrice + (lastdayHigh - 2.0 * lastdayLow)

        g_price_308 = (g_price_252 + g_price_260) / 2.0
        g_price_300 = (g_price_244 + g_price_252) / 2.0
        g_price_292 = (centrePrice + g_price_244) / 2.0
        g_price_284 = (centrePrice + g_price_316) / 2.0
        g_price_276 = (g_price_316 + g_price_324) / 2.0
        # g_price_268 = (g_price_324 + g_price_332) / 2.0

        priceList = sorted([
            preventPrice1, preventPrice2, preventPrice3, supportPrice1,
            supportPrice2, supportPrice3, centrePrice
        ],
                           reverse=True)

        priceList2 = sorted(
            [g_price_308, g_price_300, g_price_292, g_price_284, g_price_276],
            reverse=True)

        fibList3.clear()
        fibList3.extend(priceList2)

        fibList2.clear()
        fibList2.extend(priceList)

    def maSignal(self):
        """
        移动平均线信号
        """

        maValueTime = [5, 10, 20, 50, 100, 200]

        m1ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M1)
        m5ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M5)
        m15ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M15)
        m30ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M30)

        m1SMA = self.indicator.maValueForTimeArray(closeArr=m1ClosePrice,
                                                   timeArray=maValueTime)
        m5SMA = self.indicator.maValueForTimeArray(closeArr=m5ClosePrice,
                                                   timeArray=maValueTime)
        m15SMA = self.indicator.maValueForTimeArray(closeArr=m15ClosePrice,
                                                    timeArray=maValueTime)
        m30SMA = self.indicator.maValueForTimeArray(closeArr=m30ClosePrice,
                                                    timeArray=maValueTime)

        m1Ema = self.indicator.maValueForTimeArray(closeArr=m1ClosePrice,
                                                   timeArray=maValueTime,
                                                   maType=1)
        m5Ema = self.indicator.maValueForTimeArray(closeArr=m5ClosePrice,
                                                   timeArray=maValueTime,
                                                   maType=1)
        m15Ema = self.indicator.maValueForTimeArray(closeArr=m15ClosePrice,
                                                    timeArray=maValueTime,
                                                    maType=1)
        m30Ema = self.indicator.maValueForTimeArray(closeArr=m30ClosePrice,
                                                    timeArray=maValueTime,
                                                    maType=1)

        currentPrice = mt5.symbol_info_tick(self.symble).bid
        m1State = list(map(lambda x: currentPrice > x, m1SMA + m1Ema))
        m5State = list(map(lambda x: currentPrice > x, m5SMA + m5Ema))
        m15State = list(map(lambda x: currentPrice > x, m15SMA + m15Ema))
        m30State = list(map(lambda x: currentPrice > x, m30SMA + m30Ema))

        self.sendTradeMsg(m1State, m5State, m15State, m30State)

        if sum(m1State) == 12 and sum(not x for x in m1State) == 0:
            if sum(m5State) == 12 and sum(not x for x in m5State) == 0:
                if sum(m15State) == 12 and sum(not x for x in m15State) == 0:
                    if sum(m30State) == 12 and sum(not x
                                                   for x in m30State) == 0:
                        mvSingal.clear()
                        mvSingal.append([current_time(), True])
                        return
        elif sum(m1State) == 0 and sum(not x for x in m1State) == 12:
            if sum(m5State) == 0 and sum(not x for x in m5State) == 12:
                if sum(m15State) == 0 and sum(not x for x in m15State) == 12:
                    if sum(m30State) == 0 and sum(not x
                                                  for x in m30State) == 12:
                        mvSingal.clear()
                        mvSingal.append([current_time(), False])
                        return

    lastSendTime = 0
    lastSendState = 0

    def sendTradeMsg(self, m1State, m5State, m15State, m30State):
        """
        发送趋势信号
        """
        if sum(m1State) == 12 and sum(not x for x in m1State) == 0:
            if sum(m5State) == 12 and sum(not x for x in m5State) == 0:
                if sum(m15State) > 8 and sum(not x for x in m15State) < 2:
                    if sum(m30State) > 8 and sum(not x for x in m30State) < 2:
                        if current_time() - self.lastSendTime > 10 * 60:
                            if self.lastSendState != 1:
                                sendMail("出现共振上涨信号", send=True)
                                self.lastSendTime = current_time()
                                self.lastSendState = 1
                        return
        elif sum(m1State) == 0 and sum(not x for x in m1State) == 12:
            if sum(m5State) == 0 and sum(not x for x in m5State) == 12:
                if sum(m15State) < 2 and sum(not x for x in m15State) > 8:
                    if sum(m30State) < 2 and sum(not x for x in m30State) > 8:
                        if current_time() - self.lastSendTime > 10 * 60:
                            if self.lastSendState != 2:
                                sendMail("出现共振下跌信号", send=True)
                                self.lastSendTime = current_time()
                                self.lastSendState = 2
                        return

    def skillIndicatorSignal(self):
        """
        技术指标信号
        RSI、STOCH、STOCHRSI、MACD、ADX、CCI、ATR、ROC、Ultimate Oscillator、Williams %R
        Highs/Lows、Bull/Bear Power
        """

        m1ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M1)
        m5ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M5)
        m15ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M15)
        m30ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M30)

        m1HighPrice = self.getHighPriceArray(self.symble, mt5.TIMEFRAME_M1)
        m5HighPrice = self.getHighPriceArray(self.symble, mt5.TIMEFRAME_M5)
        m15HighPrice = self.getHighPriceArray(self.symble, mt5.TIMEFRAME_M15)
        m30HighPrice = self.getHighPriceArray(self.symble, mt5.TIMEFRAME_M30)

        m1LowPrice = self.getLowPriceArray(self.symble, mt5.TIMEFRAME_M1)
        m5LowPrice = self.getLowPriceArray(self.symble, mt5.TIMEFRAME_M5)
        m15LowPrice = self.getLowPriceArray(self.symble, mt5.TIMEFRAME_M15)
        m30LowPrice = self.getLowPriceArray(self.symble, mt5.TIMEFRAME_M30)

        priceList = [
            [m1ClosePrice, m1HighPrice, m1LowPrice],
            [m5ClosePrice, m5HighPrice, m5LowPrice],
            [m15ClosePrice, m15HighPrice, m15LowPrice],
            [m30ClosePrice, m30HighPrice, m30LowPrice],
        ]

        self.rsiResult = self.indicator.rsiValueForMoreTimeFrame(
            [m1ClosePrice, m5ClosePrice, m15ClosePrice, m30ClosePrice])
        self.macdResult = self.indicator.macdValueForMoreTimeFrame(
            [m1ClosePrice, m5ClosePrice, m15ClosePrice, m30ClosePrice])
        self.rocResult = self.indicator.rocValueForMoreTimeFrame(
            [m1ClosePrice, m5ClosePrice, m15ClosePrice, m30ClosePrice])
        self.adxResult = self.indicator.adxValueForMoreTimeFrame(priceList)
        self.cciResult = self.indicator.cciValueForMoreTimeFrame(priceList)
        # Williams %R
        self.willrResult = self.indicator.willrValueForMoreTimeFrame(priceList)
        # Ultimate Oscillator
        self.ultoscResult = self.indicator.ultoscValueForMoreTimeFrame(
            priceList)
        self.stochResult = self.indicator.stochValueForMoreTimeFrame(priceList)
        self.stochRsiResult = self.indicator.stochRsiValueForMoreTimeFrame(
            [m1ClosePrice, m5ClosePrice, m15ClosePrice, m30ClosePrice])
        self.atrResult = self.indicator.atrValueForMoreTimeFrame(priceList)
        self.indicatorAnalyse()

    def indicatorAnalyse(self):
        """
        指标分析
        """
        rsiValueArr = [(55 <= item <= 75) if (55 <= item <= 75) else False if
                       (25 <= item <= 45) else None for item in self.rsiResult]
        macdValueArr = [
            True if item > 0 else False for item in self.macdResult
        ]
        rocValueArr = [True if item > 0 else False for item in self.rocResult]
        adxValueArr = self.adxResult
        cciValueArr = [(45 <= item <= 180) if (45 <= item <= 180) else False if
                       (-180 <= item <= -45) else None
                       for item in self.cciResult]
        willrValueArr = [(-40 <= item <= -20) if
                         (-40 <= item <= -20) else False if
                         (-80 <= item <= -60) else None
                         for item in self.willrResult]
        ultoscValueArr = [(51 <= item <= 70) if
                          (51 <= item <= 70) else False if
                          (30 <= item <= 49) else None
                          for item in self.ultoscResult]
        # stochValueArr = [(55 <= item <= 80) if (55 <= item <= 80) else False if
        #                  (20 <= item <= 45) else None
        #                  for item in self.stochResult]
        # stochRsiValueArr = [(55 <= item <= 80) if
        #                     (55 <= item <= 80) else False if
        #                     (20 <= item <= 45) else None
        #                     for item in self.stochRsiResult]
        packArray = [
            rsiValueArr,
            macdValueArr,
            rocValueArr,
            adxValueArr,
            cciValueArr,
            willrValueArr,
            ultoscValueArr,  # stochValueArr, stochRsiValueArr
        ]
        zipped_arrays = zip(*packArray)
        m1, m5, m15, m30 = zipped_arrays

        if m1.count(True) >= 4 or m1.count(False) < 2:
            if m5.count(True) >= 4 or m5.count(False) < 2:
                if m15.count(True) >= 4 or m15.count(False) < 2:
                    if m30.count(True) >= 4 or m30.count(False) < 2:
                        indicatorSignal.clear()
                        indicatorSignal.append([current_time(), True])
                        # if mvSingal["isBuy"] == True:
                        #     if self.lastIndicatorNotice == 0 or current_time(
                        #     ) - self.lastIndicatorNotice > 600:
                        #         self.lastIndicatorNotice = current_time()
                        #         prints("多单信号产生，请及时确认")
                        #         sendMail("多单信号产生，请及时确认")
        elif m1.count(False) >= 4 or m1.count(True) < 2:
            if m5.count(False) >= 4 or m5.count(True) < 2:
                if m15.count(False) >= 4 or m15.count(True) < 2:
                    if m30.count(False) >= 4 or m30.count(True) < 2:
                        indicatorSignal.clear()
                        indicatorSignal.append([current_time(), False])
                        # if mvSingal["isBuy"] == False:
                        #     if self.lastIndicatorNotice == 0 or current_time(
                        #     ) - self.lastIndicatorNotice > 600:
                        #         self.lastIndicatorNotice = current_time()
                        #         prints("空单信号产生，请及时确认")
                        #         sendMail("空单信号产生，请及时确认")

    def mvIndicatorPrice(self):
        """
        多周期多条移动平均线的价格
        """

        maValueTime = [20, 50, 100, 200]

        d1ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_D1)
        h4ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_H4)
        h1ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_H1)
        m30ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M30)
        m15ClosePrice = self.getClosePriceArray(self.symble, mt5.TIMEFRAME_M15)

        d1SMA = self.indicator.maValueForTimeArray(closeArr=d1ClosePrice,
                                                   timeArray=maValueTime)
        h4SMA = self.indicator.maValueForTimeArray(closeArr=h4ClosePrice,
                                                   timeArray=maValueTime)
        h1SMA = self.indicator.maValueForTimeArray(closeArr=h1ClosePrice,
                                                   timeArray=maValueTime)
        m30SMA = self.indicator.maValueForTimeArray(closeArr=m30ClosePrice,
                                                    timeArray=maValueTime)
        m15SMA = self.indicator.maValueForTimeArray(closeArr=m15ClosePrice,
                                                    timeArray=maValueTime)
        d1Map = {
            str(maValueTime[index]): int(d1SMA[index])
            for index in range(0, len(d1SMA))
        }
        h4Map = {
            str(maValueTime[index]): int(h4SMA[index])
            for index in range(0, len(h4SMA))
        }
        h1Map = {
            str(maValueTime[index]): int(h1SMA[index])
            for index in range(0, len(h1SMA))
        }
        m30Map = {
            str(maValueTime[index]): int(m30SMA[index])
            for index in range(0, len(m30SMA))
        }
        m15Map = {
            str(maValueTime[index]): int(m15SMA[index])
            for index in range(0, len(m15SMA))
        }
        moreMvState = {
            "d1": d1Map,
            "h4": h4Map,
            "h1": h1Map,
            "m30": m30Map,
            "m15": m15Map
        }
        mvTimeframeValue.clear()
        mvTimeframeValue.append(moreMvState)

    def priceLevel(self):
        """
        阻力支撑位
        trend:  1:buy  2:sell
        level:  下标
        """

        trendMsg = ""
        levelMsg = ""

        price, trend, level = self.importantLevel()
        if price != None and self.lastLevelPrice != price and abs(
                self.lastLevelPrice - price) > 8:
            if trend != None:
                trendMsg = ("支撑" if trend == 1 else "阻力")

            if level != None:
                if trend == 1:
                    levelMsg = ("第三" if level == 0 else
                                ("第二" if level == 1 else
                                 ("第一" if level == 2 else "")))
                else:
                    levelMsg = ("第一" if level == 0 else
                                ("第二" if level == 1 else
                                 ("第三" if level == 2 else "")))
            self.lastLevelPrice = price

            noticeMsg = "当前价格到达" + levelMsg + trendMsg + "位，" + str(price)
            saveLog(noticeMsg)
            sendMail(noticeMsg, timer=False)
